/* eslint-disable react/destructuring-assignment */
import { useThrottleEffect } from 'ahooks';
import React, { useCallback, useMemo, useState } from 'react';
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import { SvgIcon } from '@/components/icon';
import { RuntimeEdgeStatusEnum } from '@/types/workflow/constant';

import { WorkflowContext } from '../context';

// 添加流动动画的样式
const flowingAnimation = `
  @keyframes flowingDash {
    to {
      stroke-dashoffset: -16;
    }
  }
`;

const ButtonEdge = (props: EdgeProps) => {
  const { nodes, nodeList, onEdgesChange, workflowDebugData, hoverEdgeId } = useContextSelector(
    WorkflowContext,
    (v) => v,
  );

  const {
    id,
    sourceX,
    sourceY,
    targetX,
    targetY,
    sourcePosition,
    targetPosition,
    selected,
    source,
    sourceHandleId,
    target,
    targetHandleId,
    style,
  } = props;

  // If parentNode is folded, the edge will not be displayed
  // 线两端节点有父节点时，父节点折叠时，线不显示
  const edgeParentNode = useMemo(() => {
    return nodeList.find(
      (node) => (node.nodeId === source || node.nodeId === target) && node.parentNodeId,
    );
  }, [nodeList, source, target]);

  const parentNode = useMemo(() => {
    return nodeList.find((node) => node.nodeId === edgeParentNode?.parentNodeId);
  }, [nodeList, edgeParentNode]);

  const defaultZIndex = useMemo(
    () => (nodeList.find((node) => node.nodeId === source && node.parentNodeId) ? 2002 : 0),
    [nodeList, source],
  );

  const onDelConnect = useCallback(
    (id: string) => {
      onEdgesChange([
        {
          type: 'remove',
          id,
        },
      ]);
    },
    [onEdgesChange],
  );

  // Selected edge or source/target node selected
  const [highlightEdge, setHighlightEdge] = useState(false);
  useThrottleEffect(
    () => {
      const connectNode = nodes.find((node) => {
        return node.selected && (node.id === props.source || node.id === props.target);
      });
      setHighlightEdge(!!connectNode || !!selected);
    },
    [nodes, selected, props.source, props.target],
    {
      wait: 100,
    },
  );

  const [, labelX, labelY] = getBezierPath({
    sourceX,
    sourceY,
    sourcePosition,
    targetX,
    targetY,
    targetPosition,
  });

  const isToolEdge = false;
  const isHover = hoverEdgeId === id;

  const { newTargetX, newTargetY } = useMemo(() => {
    if (targetPosition === 'left') {
      return {
        newTargetX: targetX - 3,
        newTargetY: targetY,
      };
    }
    if (targetPosition === 'right') {
      return {
        newTargetX: targetX + 3,
        newTargetY: targetY,
      };
    }
    if (targetPosition === 'bottom') {
      return {
        newTargetX: targetX,
        newTargetY: targetY + 3,
      };
    }
    if (targetPosition === 'top') {
      return {
        newTargetX: targetX,
        newTargetY: targetY - 3,
      };
    }
    return {
      newTargetX: targetX,
      newTargetY: targetY,
    };
  }, [targetPosition, targetX, targetY]);

  const edgeColor = useMemo(() => {
    const targetEdge = workflowDebugData?.runtimeEdges.find(
      (edge) => edge.sourceHandle === sourceHandleId && edge.targetHandle === targetHandleId,
    );
    if (!targetEdge) {
      if (highlightEdge) return '#0080FF';
      return '#99ccff';
    }

    // debug mode
    const colorMap = {
      [RuntimeEdgeStatusEnum.active]: '#0080FF',
      [RuntimeEdgeStatusEnum.waiting]: '#5E8FFF',
      [RuntimeEdgeStatusEnum.skipped]: '#8A95A7',
    };
    return colorMap[targetEdge.status];
  }, [highlightEdge, sourceHandleId, targetHandleId, workflowDebugData?.runtimeEdges]);

  const memoEdgeLabel = useMemo(() => {
    const arrowTransform = (() => {
      if (targetPosition === 'left') {
        return `translate(-85%, -47%) translate(${newTargetX}px,${newTargetY}px) rotate(0deg)`;
      }
      if (targetPosition === 'right') {
        return `translate(-10%, -50%) translate(${newTargetX}px,${newTargetY}px) rotate(-180deg)`;
      }
      if (targetPosition === 'bottom') {
        return `translate(-50%, -20%) translate(${newTargetX}px,${newTargetY}px) rotate(-90deg)`;
      }
      if (targetPosition === 'top') {
        return `translate(-50%, -90%) translate(${newTargetX}px,${newTargetY}px) rotate(90deg)`;
      }
    })();
    return (
      <EdgeLabelRenderer>
        {!parentNode?.isFolded && (
          <>
            <div
              className={`flex ${
                isHover || highlightEdge ? 'flex' : 'hidden'
              } absolute h-4 w-4 cursor-pointer items-center justify-center rounded-2xl ${
                highlightEdge || isHover ? 'bg-@brand-color text-white' : ''
              } hover:bg-@brand-color-hover hover:text-white`}
              // transform={`translate(-55%, -50%) translate(${labelX}px,${labelY}px)`}
              style={{
                transform: `translate(-55%, -50%) translate(${labelX}px,${labelY}px)`,
                zIndex: defaultZIndex + 1000,
                pointerEvents: 'all',
              }}
              onClick={() => onDelConnect(id)}
            >
              <SvgIcon
                icon="close"
                color="#fff"
                size={12}
                className={`${highlightEdge ? 'font-bold' : ''}`}
              />
            </div>
            <div
              className={`absolute flex items-center justify-center ${
                highlightEdge ? 'h-4 w-4' : 'h-3 w-3'
              }`}
              style={{
                transform: arrowTransform,
                zIndex: highlightEdge ? defaultZIndex + 1000 : defaultZIndex,
                pointerEvents: 'all',
              }}
            />
          </>
        )}
      </EdgeLabelRenderer>
    );
  }, [
    parentNode,
    isHover,
    highlightEdge,
    labelX,
    labelY,
    defaultZIndex,
    targetPosition,
    newTargetX,
    newTargetY,
    onDelConnect,
    id,
  ]);

  const memoBezierEdge = useMemo(() => {
    const targetEdge = workflowDebugData?.runtimeEdges.find(
      (edge) => edge.source === source && edge.target === target,
    );

    const edgeStyle: React.CSSProperties = (() => {
      if (!targetEdge) {
        return {
          ...style,
          ...(highlightEdge || isHover
            ? {
                strokeWidth: 2,
              }
            : { strokeWidth: 2, zIndex: 2, strokeDasharray: '8 8' }),
        };
      }

      return {
        ...style,
        strokeWidth: 2,
      };
    })();

    return (
      <>
        <style>{flowingAnimation}</style>
        {!parentNode?.isFolded && (
          <BezierEdge
            {...props}
            targetX={newTargetX}
            targetY={newTargetY}
            style={{
              ...edgeStyle,
              stroke: edgeColor,
              animation: 'flowingDash 1s linear infinite',
              display: parentNode?.isFolded ? 'none' : 'block',
            }}
          />
        )}
      </>
    );
  }, [
    workflowDebugData?.runtimeEdges,
    props,
    newTargetX,
    newTargetY,
    edgeColor,
    source,
    target,
    style,
    highlightEdge,
    parentNode,
    isHover,
  ]);

  return (
    <>
      {memoBezierEdge}
      {memoEdgeLabel}
    </>
  );
};

export default React.memo(ButtonEdge);
